﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using static MvCamCtrl.NET.MyCamera;
using Color = System.Drawing.Color;
using MvCamCtrl.NET;
using PixelFormat = System.Drawing.Imaging.PixelFormat;
using NewDevice;

namespace WpfCommonCtlTest.ViewModels
{
    public struct HKCameraInfo
    {
        public MV_CC_DEVICE_INFO device;
        public MyCamera Cam_Info;
    }

    public partial class CameraViewModel : ObservableObject
    {
        public CameraViewModel()
        {
            CameraName = new();
        }

        //所有的输入相机
        private MyCamera.MV_CC_DEVICE_INFO_LIST m_pDeviceList;

        private MyCamera.cbOutputExdelegate ImageCallback;
        private HKCameraInfo Cameras;
        [ObservableProperty] private ObservableCollection<string> cameraName;
        [ObservableProperty] private BitmapSource cameraImage;
        [ObservableProperty] private string expures;

        /// <summary>
        /// 扫描相机
        /// </summary>
        [RelayCommand]
        private void ScanCamera()
        {
            int nRet = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref m_pDeviceList);

            int m_nDevNum = (int)m_pDeviceList.nDeviceNum;

            for (int i = 0, j = 0; j < m_nDevNum; ++i, ++j)
            {
                MyCamera.MV_CC_DEVICE_INFO device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_pDeviceList.pDeviceInfo[j], typeof(MyCamera.MV_CC_DEVICE_INFO));
                if (device.nTLayerType == MyCamera.MV_USB_DEVICE)
                {
                    IntPtr buffer = Marshal.UnsafeAddrOfPinnedArrayElement(device.SpecialInfo.stUsb3VInfo, 0);

                    MyCamera.MV_USB3_DEVICE_INFO gigeInfo = (MyCamera.MV_USB3_DEVICE_INFO)Marshal.PtrToStructure(buffer, typeof(MyCamera.MV_USB3_DEVICE_INFO));

                    CameraName.Add(gigeInfo.chUserDefinedName);
                }
            }
        }

        private HKCamera camera;

        /// <summary>
        /// 连接相机
        /// </summary>
        [RelayCommand]
        private void ConnectCamera()
        {
            camera = new(CameraName[0], ImageType.Bitmap);
            if (camera.Open() == 0)
            {
                Debug.WriteLine("相机打开成功");
            }

            //    Cameras = new HKCameraInfo();
            //    MyCamera.MV_CC_DEVICE_INFO device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_pDeviceList.pDeviceInfo[0], typeof(MyCamera.MV_CC_DEVICE_INFO));
            //    Cameras.device = device;
            //    Cameras.Cam_Info = new MyCamera();
            //    int ret = Cameras.Cam_Info.MV_CC_CreateDevice_NET(ref Cameras.device);
            //    var ok1 = Cameras.Cam_Info.MV_CC_OpenDevice_NET();
            //    Cameras.Cam_Info.MV_CC_SetTriggerMode_NET(1);
            //    Cameras.Cam_Info.MV_CC_SetTriggerSource_NET(7);
            //    // ch:注册回调函数 | en:Register image callback
            //    ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);

            //    int nRet = Cameras.Cam_Info.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
            //    int nRet2 = NecessaryOperBeforeGrab();
            //    if (MyCamera.MV_OK != nRet2)
            //    {
            //    }
            //    int ret3 = 0;
            //    ret3 = Cameras.Cam_Info.MV_CC_StartGrabbing_NET();
        }

        /// <summary>
        /// 单次采集
        /// </summary>
        [RelayCommand]
        private async void OneTimesCollection()
        {
            if (await camera.TriggerImage() == 0)
            {
                Debug.WriteLine("c采集图片成功");

                var rawimage = (Bitmap)camera.GetImage();
                Application.Current.Dispatcher.Invoke(() =>
                    {
                        CameraImage = ConvertToBitmapSource(rawimage);
                        rawimage.Dispose(); // 释放资源
                    });
            }

            //    bool isSucsses = true;
            //    _isImageReady = false;
            //    Cameras.Cam_Info.MV_CC_TriggerSoftwareExecute_NET();
            //    Stopwatch stopwatch = Stopwatch.StartNew();
            //    await Task.Run(async () =>
            //    {
            //        while (!_isImageReady)
            //        {
            //            if (stopwatch.ElapsedMilliseconds > 5000)
            //            {
            //                isSucsses = false;
            //                break;
            //            }
            //            await Task.Delay(100);
            //        }
            //    });

            //    if (isSucsses)
            //    {
            //        Application.Current.Dispatcher.Invoke(() =>
            //        {
            //            CameraImage = ConvertToBitmapSource(_rawImage);
            //            _rawImage.Dispose(); // 释放资源
            //        });
            //    }
        }

        private BitmapSource ConvertToBitmapSource(Bitmap bitmap)
        {
            var rect = new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height);
            var bitmapData = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);
            try
            {
                return BitmapSource.Create(
                    bitmapData.Width, bitmapData.Height, 96, 96,
                    PixelFormats.Gray8, null,
                    bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
            }
            finally
            {
                bitmap.UnlockBits(bitmapData);
            }
        }

        /// <summary>
        /// 持续采集
        /// </summary>
        [RelayCommand]
        private void KeepCollection()
        {
        }

        /// <summary>
        /// 停止持续采集
        /// </summary>
        [RelayCommand]
        private void StopKeepCollection()
        {
        }

        /// <summary>
        /// 设定曝光
        /// </summary>
        [RelayCommand]
        private void SetExpure()
        {
            if (float.TryParse(Expures, out float value))
            {
                camera.SetExposure(value);
            }
        }

        /// <summary>
        /// 关闭
        /// </summary>
        [RelayCommand]
        private void DisposeCamera()
        {
            camera.Close();
            //var ret = Cameras.Cam_Info.MV_CC_CloseDevice_NET();
            //var ret2 = Cameras.Cam_Info.MV_CC_DestroyDevice_NET();
        }

        private object obj = new object();
        private Bitmap _rawImage;
        private bool _isImageReady = false;

        private void ImageCallbackFunc(IntPtr pData, ref MyCamera.MV_FRAME_OUT_INFO_EX stFrameInfo, IntPtr pUser)
        {
            try
            {
                DateTime d11 = DateTime.Now;
                lock (obj)
                {
                    _rawImage = Inptr2Bitmap(pData, ref stFrameInfo, pUser);

                    _isImageReady = true;
                    // _rawImage.Dispose();
                }
            }
            catch (Exception E)
            {
                throw E;
            }
        }

        private Bitmap Inptr2Bitmap(IntPtr pData, ref MyCamera.MV_FRAME_OUT_INFO_EX stFrameInfo, IntPtr pUser)
        {
            Bitmap bmp = null;

            DateTime dStart = DateTime.Now;

            bmp = new Bitmap(stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.nWidth * 1, PixelFormat.Format8bppIndexed, pData);
            // set palette back
            bmp.Palette = GrayPalette;

            Debug.WriteLine("HK-grayIMAGE CT:" + DateTime.Now.Subtract(dStart).TotalMilliseconds.ToString("0.000") + "ms");

            return bmp;
        }

        private static ColorPalette grayPalette = null;
        private PixelFormat m_bitmapPixelFormat = PixelFormat.DontCare;
        private UInt32 m_nBufSizeForDriver = 0;
        private IntPtr m_BufForDriver = IntPtr.Zero;
        private IntPtr m_ConvertDstBuf = IntPtr.Zero;
        private UInt32 m_nConvertDstBufLen = 0;

        public static ColorPalette GrayPalette
        {
            get
            {
                if (grayPalette != null) return grayPalette;
                Bitmap bm = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
                grayPalette = bm.Palette;
                for (int i = 0; i < grayPalette.Entries.Length; i++)
                {
                    grayPalette.Entries[i] = System.Drawing.Color.FromArgb(i, i, i);
                }
                return grayPalette;
            }
        }

        // ch:取图前的必要操作步骤 | en:Necessary operation before grab
        private Int32 NecessaryOperBeforeGrab()
        {
            // ch:取图像宽 | en:Get Iamge Width
            MyCamera.MVCC_INTVALUE_EX stWidth = new MyCamera.MVCC_INTVALUE_EX();
            int nRet = Cameras.Cam_Info.MV_CC_GetIntValueEx_NET("Width", ref stWidth);
            if (MyCamera.MV_OK != nRet)
            {
                //ShowErrorMsg("Get Width Info Fail!", nRet);
                return nRet;
            }
            // ch:取图像高 | en:Get Iamge Height
            MyCamera.MVCC_INTVALUE_EX stHeight = new MyCamera.MVCC_INTVALUE_EX();
            nRet = Cameras.Cam_Info.MV_CC_GetIntValueEx_NET("Height", ref stHeight);
            if (MyCamera.MV_OK != nRet)
            {
                //ShowErrorMsg("Get Height Info Fail!", nRet);
                return nRet;
            }
            // ch:取像素格式 | en:Get Pixel Format
            MyCamera.MVCC_ENUMVALUE stPixelFormat = new MyCamera.MVCC_ENUMVALUE();
            nRet = Cameras.Cam_Info.MV_CC_GetEnumValue_NET("PixelFormat", ref stPixelFormat);
            if (MyCamera.MV_OK != nRet)
            {
                //ShowErrorMsg("Get Pixel Format Fail!", nRet);
                return nRet;
            }

            // ch:设置bitmap像素格式，申请相应大小内存 | en:Set Bitmap Pixel Format, alloc memory
            if ((Int32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Undefined == stPixelFormat.nCurValue)
            {
                //ShowErrorMsg("Unknown Pixel Format!", MyCamera.MV_E_UNKNOW);
                return MyCamera.MV_E_UNKNOW;
            }
            else if (IsMono(stPixelFormat.nCurValue))
            {
                m_bitmapPixelFormat = PixelFormat.Format8bppIndexed;

                if (IntPtr.Zero != m_ConvertDstBuf)
                {
                    Marshal.Release(m_ConvertDstBuf);
                    m_ConvertDstBuf = IntPtr.Zero;
                }

                // Mono8为单通道
                m_nConvertDstBufLen = (UInt32)(stWidth.nCurValue * stHeight.nCurValue);
                m_ConvertDstBuf = Marshal.AllocHGlobal((Int32)m_nConvertDstBufLen);
                if (IntPtr.Zero == m_ConvertDstBuf)
                {
                    //ShowErrorMsg("Malloc Memory Fail!", MyCamera.MV_E_RESOURCE);
                    return MyCamera.MV_E_RESOURCE;
                }
            }
            else
            {
                m_bitmapPixelFormat = PixelFormat.Format24bppRgb;

                if (IntPtr.Zero != m_ConvertDstBuf)
                {
                    Marshal.FreeHGlobal(m_ConvertDstBuf);
                    m_ConvertDstBuf = IntPtr.Zero;
                }

                // RGB为三通道
                m_nConvertDstBufLen = (UInt32)(3 * stWidth.nCurValue * stHeight.nCurValue);
                m_ConvertDstBuf = Marshal.AllocHGlobal((Int32)m_nConvertDstBufLen);
                if (IntPtr.Zero == m_ConvertDstBuf)
                {
                    //ShowErrorMsg("Malloc Memory Fail!", MyCamera.MV_E_RESOURCE);
                    return MyCamera.MV_E_RESOURCE;
                }
            }

            // 确保释放保存了旧图像数据的bitmap实例，用新图像宽高等信息new一个新的bitmap实例
            if (null != _rawImage)
            {
                _rawImage.Dispose();
                _rawImage = null;
            }
            _rawImage = new Bitmap((Int32)stWidth.nCurValue, (Int32)stHeight.nCurValue, m_bitmapPixelFormat);

            // ch:Mono8格式，设置为标准调色板 | en:Set Standard Palette in Mono8 Format
            if (PixelFormat.Format8bppIndexed == m_bitmapPixelFormat)
            {
                ColorPalette palette = _rawImage.Palette;
                for (int i = 0; i < palette.Entries.Length; i++)
                {
                    palette.Entries[i] = Color.FromArgb(i, i, i);
                }
                _rawImage.Palette = palette;
            }

            return MyCamera.MV_OK;
        }

        private Boolean IsMono(UInt32 enPixelType)
        {
            switch (enPixelType)
            {
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono1p:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono2p:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono4p:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8_Signed:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10_Packed:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12_Packed:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono14:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono16:
                    return true;

                default:
                    return false;
            }
        }
    }
}